/*

    tools23d - tools for converting images to 3D formats.
    Copyright (C) 2014  Dave Gorst

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/


/**
 * @file   cli-common.c
 * @brief  Commandline option functions common to both btime23d and photo23d.
 *
 */

/*
 * WARNING : Testing sequences consisting of a percentage sign and then hexadecimal digits will be converted to the ASCII equivalent character when debugging in MSVC 2010!
 *
 * Use "%25" in place of "%" to get around this.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>

#include "tools23d.h"

#ifdef BUILD_BTIME
	#include "btime23d.h"
	#include "cli-btime.h"
#else
	#include "photo23d.h"
	#include "cli-photo.h"
#endif

#include "cli-common.h"
#include "cli.h"
#include "readml.h"
#include "system.h"
#include "util.h"

option common_options_table [26] =
{
	{T3D_SetAutocrop, "autocrop",
		"Perform cropping on the original image to \n"
		"convert it to the desired aspect ratio \n"
		"e.g. if converting from 4:3 to 16:9 \"letterbox\"\n"
		"by removing the top and/or bottom of the picture.\n"
		"Valid values are top, centre, and bottom.\n"
		"\n\n"},       /* 'a'  */
    {T3D_SetDepth,"bitdepth",
		"Set bit depth of output images.\n\n"
	},        /* 'b'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'c'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'd'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'e'  */
	{T3D_SetFilter,"filter",
		"Specify filter to use when resizing.\n"
		"Valid values are :\n"
		"  box, bicubic, bspline, catmullrom, \n"
		"  and lanczos3.\n\n"
	},                 /* 'f'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'g'  */
	{T3D_DisplayHelp,"help","Display this help text.\n\n"},               /* 'h'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'i'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'j'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'k'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'l'  */
    {T3D_SetMode,"mode",
		"3D output mode\n"
		"Valid values are :\n"
		"  SBS (half Side By Side)\n"
		"  FSBS (Full Side By Side)\n"
		"  OU (Over and Under)\n"
		"  FHD3D (Full High Definition 3D)\n\n"
	},        /* 'm'  */
    {T3D_SetScale,"newsize",
		"Scale output to dimensions X by Y.\n\n"},        /* 'n'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'o'  */
	{T3D_SetPreserveAR,"preserve-ar",
		"Preserve original aspect ratio of input files.\n\n"},  /* 'p'  */
	{T3D_SetLogLevel,"quiet",
		"Keep schtum.\n\n"
	},    /* 'q'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'r'  */
	{T3D_SetSort,"sort",
		"Set sort order\n"
		"Valid values are:\n"
		"  alphanumeric\n"
		"  filechangetime\n\n"
		},        /* 's'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 't'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'u'  */
	{T3D_SetLogLevel,"verbose",
		"Be garrulous.\n\n"
	},    /* 'v'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'w'  */
    {T3D_GeneralUnknown,NULL,NULL},        /* 'x'  */
    {T3D_SetAlwaysYes,"yes","Always continue if warning is raised.\n\n"},        /* 'y'  */
    {T3D_GeneralUnknown,NULL,NULL}         /* 'z'  */
};

/**
Initialise user interface.

@param cli_params   Pointer to structure holding user-selected options.
@return ::TRUE on success.
*/

BOOL T3D_InitialiseUI (params * cli_params)
{
	T3D_ClearGeneralParams (cli_params);
	T3D_ClearAppParams (cli_params);

	/* NOTE : CLI initialisation always returns TRUE. This parameter is provided for use when we add a GUI. */

	return TRUE;
}

/**
Shutdown user interface.

@param cli_params   Pointer to structure holding user-selected options.
*/

void T3D_ShutdownUI (params * cli_params)
{
	T3D_FreeAppParams (cli_params);
}

/**
Clear non-application specific user option values.

@param cli_params   Pointer to structure holding user-selected options.
*/

void T3D_ClearGeneralParams (params * cli_params)
{
	/* Set default values. */

	cli_params->preserve_aspect_ratio = FALSE;
	cli_params->mode = HSBS;
	cli_params->filter = Lanczos3;
	cli_params->loglevel = Standard;
	cli_params->croptype = None;
	cli_params->sorttype = Alphanumeric;

	/* Unset */
	cli_params->width = 0;
	cli_params->height = 0;
	cli_params->depth = 0;

	cli_params->always_yes = FALSE;
	cli_params->output_filename = NULL;

}


/**
Shutdown user interface.

@param cli_params   Pointer to structure holding user-selected options.
*/

t3d_return T3D_SetGeneralDefaults (params * cli_params)
{
	t3d_return retcode = t3d_success;

	/* If specifying output colour depth, warn if anything unusual is being asked for. */

	if (cli_params->depth)
	{
		if ((cli_params->depth != 15) && (cli_params->depth != 16) && (cli_params->depth != 24) && (cli_params->depth != 32))
		{
			retcode = T3D_RaiseWarning (&cli_params->always_yes, "Non-standard colour depths may cause unexpected results.") ? t3d_success : t3d_bad_parameter;
		}
	}
	else
		cli_params->depth = 32;

	/* If scaling give warning for non-standard resolutions. */
	/* If unset default to standard 1920x1080, or 1920x2205 for FHD3D. */

	if (retcode == t3d_success)
	{
		if ((cli_params->width) || (cli_params->height))
		{
			if
			(
				((cli_params->mode == FHD3D) && ((cli_params->width != 1920) || (cli_params->height != 2205)))
				||
				((cli_params->mode == FSBS) && ((cli_params->width != 3840) || (cli_params->height != 1080)))
				||
				(!
					(
						((cli_params->width == 1920) && (cli_params->height == 1080)) ||	/* 1080p */
						((cli_params->width == 1280) && (cli_params->height == 720))		/* 720p */
					)
				)
			)
				if (cli_params->loglevel > Quiet)
					retcode = T3D_RaiseWarning
					(
						&cli_params->always_yes,
						"Non-standard resolutions may cause unexpected results."
					) ? t3d_success : t3d_bad_parameter;

			/* TODO - Do we need a cli_fail/abort return code? */
		}
		else
		{
			cli_params->width = cli_params->mode == FSBS ? 3840 : 1920;
			cli_params->height = cli_params->mode == FHD3D ? 2205 : 1080;
		}
	}
	return retcode;
}

/**
This function is called if no known common option has been found. It calls the relevant application-specific option in order to check if that has been set.
*/

OPTIONFUNCTION (T3D_GeneralUnknown)
{
	return app_options_table [input_char - 'a'].func (input_char, cli_params, arg, argc, argv);
}

/**
Set flag indicating that we should preserve the aspect ratio of the original input file.
*/

OPTIONFUNCTION (T3D_SetPreserveAR)
{
	cli_params->preserve_aspect_ratio = TRUE;

	return t3d_success;
}

/**
Specify the filter for use during resize
*/

OPTIONFUNCTION (T3D_SetFilter)
{
	if (strcmp (argv [*arg], "box") == 0)
		cli_params->filter = Box;
	else if (strcmp (argv [*arg], "bicubic") == 0)
		cli_params->filter = Bicubic;
	else if (strcmp (argv [*arg], "bilinear") == 0)
		cli_params->filter = Bilinear;
	else if (strcmp (argv [*arg], "bspline") == 0)
		cli_params->filter = BSpline;
	else if (strcmp (argv [*arg], "catmullrom") == 0)
		cli_params->filter = CatmullRom;
	else if (strcmp (argv [*arg], "lanczos3") == 0)
		cli_params->filter = Lanczos3;
	else
	{
		T3D_SetLastError ("Unknown filter \"%s\" - valid values are box, bicubic, bilinear, bspline, catmullrom and lanczos3.", argv [*arg]);
		return t3d_bad_parameter;
	}

	++*arg;

	return t3d_success;
}

/**
Specify how the input files will be sorted.
*/

OPTIONFUNCTION (T3D_SetSort)
{
	if (strcmp (argv [*arg], "alphanumeric") == 0)
		cli_params->sorttype = Alphanumeric;
	else if (strcmp (argv [*arg], "filechangetime") == 0)
		cli_params->sorttype = Filechangetime;
	else
	{
		T3D_SetLastError ("Unknown sort type \"%s\" - valid values are alphanumeric and filechangetime.", argv [*arg]);
		return t3d_bad_parameter;
	}

	++*arg;

	return t3d_success;
}

/**
Specify the output file mode as Side-By-Side, Over-and-Under, FHD3D etc.
*/

OPTIONFUNCTION (T3D_SetMode)
{
	if ((strcmp (argv [*arg], "HSBS") == 0) || (strcmp (argv [*arg], "SBS") == 0))
		cli_params->mode = HSBS;
	else if (strcmp (argv [*arg], "FSBS") == 0)
		cli_params->mode = FSBS;
	else if (strcmp (argv [*arg], "OU") == 0)
		cli_params->mode = OU;
	else if (strcmp (argv [*arg], "FHD3D") == 0)
		cli_params->mode = FHD3D;
	else
	{
		T3D_SetLastError ("Unknown mode \"%s\" - valid values are SBS, OU or FHD3D.", argv [*arg]);
		return t3d_bad_parameter;
	}
	++(*arg);
	return t3d_success;
}

/**
Set the logging level.
*/

OPTIONFUNCTION (T3D_SetLogLevel)
{
	if (cli_params->loglevel != Standard)
	{
		T3D_SetLastError ("You cannot specify quiet and verbose options simultaneously.");
		return t3d_bad_parameter;
	}
	else
		cli_params->loglevel = (input_char == 'q' ? Quiet : Verbose);

	if (cli_params->loglevel == Verbose)
		T3D_OutputMessage ("Logging level set as verbose.\n");

	return t3d_success;
}

/**
Set the size of the output picture.
*/

OPTIONFUNCTION (T3D_SetScale)
{
	if (!T3D_ConvertXYToInts(argv [*arg], &cli_params->width, &cli_params->height))
	{
		T3D_SetLastError ("Malformed input value supplied for scale.");
		return t3d_bad_parameter;
	}
	++*arg;
	return t3d_success;
}


/**
Set colour depth of output images.
*/

OPTIONFUNCTION (T3D_SetDepth)
{
	if ((cli_params->depth = (unsigned char) atoi (argv [*arg])) == ERANGE)
		return t3d_bad_parameter;
	++(*arg);
	return t3d_success;
}

/**
Set flag indicating that we should always respond "yes" when ::T3D_RaiseWarning is called.
*/

OPTIONFUNCTION (T3D_SetAlwaysYes)
{
	cli_params->always_yes = TRUE;

	return t3d_success;
}

/**
Set flag indicating that user requires help to be displayed.
*/

OPTIONFUNCTION (T3D_DisplayHelp)
{
	return t3d_displayhelp;
}

/**
Specify whether we should take the top, middle or bottom section of the image when cropping full frame to widescreen.
*/

OPTIONFUNCTION (T3D_SetAutocrop)
{
	if (strcmp (argv [*arg], "top") == 0)
		cli_params->croptype = Top;
	else if (strcmp (argv [*arg], "middle") == 0)
		cli_params->croptype = Centre;
	else if (strcmp (argv [*arg], "bottom") == 0)
		cli_params->croptype = Bottom;
	else
	{
		T3D_SetLastError("Unknown crop type - should be top, middle or bottom.");
		return t3d_bad_parameter;
	}

	++*arg;

	return t3d_success;
}

/**
Display text explaining printf style specifiers used when specifying output filename pattern.
*/

void T3D_PrintFooter (void)
{
	T3D_OutputMessage (
		"\n\nThe following print specifiers can be used when specifying the output filename :\n\n"
		"    %%d - sequence number.\n"
		"    %%h - hour of file creation (24 hour clock).\n"
		"    %%m - minute of file creation.\n"
		"    %%s - second of file creation.\n"
		"    %%Y - year of file creation (4 digits).\n"
		"    %%M - month of file creation.\n"
		"    %%D - day of file creation.\n\n");

	T3D_OutputMessage (
		"The output width may also be specified e.g. %%3d will give a maximum width of 3\n"
		"digits. If prefixed with a zero the output value will be left zero padded e.g. \n"
		"specifying %%03d with a sequence number of 1 will give you \"001\".\n\n"
	);
}
